<!DOCTYPE html>
<html>

<head>
  <meta charset='utf-8'>
  <title>鼠标控制物体旋转</title>
  <link rel="shortcut icon" href="../icon/sparrow.png" />
  <link rel="bookmark" href="../icon/sparrow.png" type="image/x-icon" />
  <link rel="stylesheet" href="../style/common.css" />
  <!-- 对于制作原型或学习，你可以这样使用最新版本： -->
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src="../lib/webgl-debug.js"></script>
  <script src="../lib/webgl-utils.js"></script>
  <script src="../lib/cuon-matrix.js"></script>
  <script src="../lib/cuon-utils.js"></script>
  <script src="../lib/allx-utils.js"></script>
</head>

<body>

  <div id='gl36'>
    <h2>gl36 鼠标控制物体旋转</h2>
    <canvas id="c36" width="400" height="400">
      您的浏览器不支持canvas
    </canvas>

    <script type="text/javascript">
      // 顶点着色器程序2
      let VSHADER_SOURCE36 = `
        attribute vec4 a_Position; // 顶点坐标
        attribute vec2 a_TexCoord; // 纹理坐标
        attribute vec4 a_Normal; // 法向量

        uniform mat4 u_MvpMatrix; // 模型视图投影矩阵
        uniform mat4 u_ModelMatrix; // 模型矩阵
        uniform mat4 u_NormalMatrix; // 用来变换法向量的矩阵

        varying vec3 v_Normal;
        varying vec3 v_Position;
        varying vec2 v_TexCoord;

        void main(){
          gl_Position = u_MvpMatrix * a_Position;
          v_Position = vec3(u_ModelMatrix * a_Position); // 计算顶点的世界坐标
          v_Normal = normalize(vec3(u_NormalMatrix * a_Normal)); // 计算变换后的法向量并归一化法向量
          v_TexCoord = a_TexCoord;
        }`;

      // 片元着色器程序2
      let FSHADER_SOURCE36 = `
        precision mediump float; // 声明片元着色器float的精度（必须指定）

        uniform sampler2D u_Sampler; // 纹理采样
        uniform vec3 u_LightColor; // 光线颜色
        uniform vec3 u_LightPosition; // 光源位置（世界坐标系）
        uniform vec3 u_AmbientLight; // 环境光颜色

        varying vec3 v_Normal; 
        varying vec3 v_Position;
        varying vec2 v_TexCoord;

        void main(){
          vec4 color = texture2D(u_Sampler, v_TexCoord);
          vec3 normal = normalize(v_Normal); // 对插值后的法向量进行归一化（内插后长度不一定为1.0）
          vec3 lightDirection = normalize(u_LightPosition - v_Position); // 计算光线方向并归一化
          float nDotL = max(dot(lightDirection, normal), 0.0); // 计算光线方向和法向量的点积

          vec3 diffuse = u_LightColor * vec3(color) * nDotL; // 计算漫反射光的颜色
          vec3 ambient = u_AmbientLight * color.rgb; // 计算环境反射光颜色

          gl_FragColor = vec4(diffuse + ambient, color.a); // 漫反射光 + 环境反射光
        }`;

      const c36 = document.querySelector("#c36");
      const gl36 = getWebGLContext(c36); // 获取canvas，获取webGL绘图上下文
      if (!gl36) console.log(Error("无法获得webgl的绘图上下文"));

      if (!initShaders(gl36, VSHADER_SOURCE36, FSHADER_SOURCE36)) console.log(Error("无法初始化着色器")); // 初始化着色器

      let n36 = initVertexBuffers36(gl36); // 设置顶点信息（传入attribute变量），返回绘制次数
      if (n36 < 0) console.log(Error("设置顶点着色器缓冲区信息"));

      gl36.enable(gl36.DEPTH_TEST); // 开启深度检测（隐藏面消除）
      gl36.clearColor(0.0, 0.0, 0.0, 1.0); // 设置背景色

      // 获取 uniform 变量位置
      let u_mvpMatrix36 = gl36.getUniformLocation(gl36.program, "u_MvpMatrix");
      let u_modelMatrix36 = gl36.getUniformLocation(gl36.program, "u_ModelMatrix");
      let u_normalMatrix36 = gl36.getUniformLocation(gl36.program, "u_NormalMatrix");
      let u_lightColor36 = gl36.getUniformLocation(gl36.program, "u_LightColor");
      let u_ambientLight36 = gl36.getUniformLocation(gl36.program, "u_AmbientLight");
      let u_lightPosition36 = gl36.getUniformLocation(gl36.program, "u_LightPosition");
      // let u_sampler36 = gl36.getUniformLocation(gl36.program, "u_Sampler");

      gl36.uniform3f(u_lightColor36, 1.0, 1.0, 1.0); // 传入 白色光线
      gl36.uniform3f(u_ambientLight36, 0.1, 0.1, 0.1); // 传入 环境光颜色 更真实
      gl36.uniform3f(u_lightPosition36, 20.0, 20.0, 40.0); // 传入 点光源位置（世界坐标）

      let g_modelMatrix36 = new Matrix4(); // 全局 模型矩阵
      let g_viewProjMatrix36 = new Matrix4(); // 创建视图投影矩阵
      let g_mvpMatrix36 = new Matrix4(); // 全局 模型视图投影矩阵
      let g_normalMatrix36 = new Matrix4(); // 全局 魔法矩阵 

      let currentAngle36 = [0.0, 0.0]; // [X轴旋转角度, Y轴旋转角度]

      if (!initTextures36(gl36, n36)) console.log(Error("无法配置纹理")); // 配置纹理

      function tick36() {
        draw36(gl36, n36, g_viewProjMatrix36, u_mvpMatrix36, currentAngle36);
        requestAnimationFrame(tick36, c36);
      }
      tick36();

      function initVertexBuffers36(gl) {
        var vertices = new Float32Array([
          1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, // v0-v1-v2-v3 front
          1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, // v0-v3-v4-v5 right
          1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, // v0-v5-v6-v1 up
          -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, // v1-v6-v7-v2 left
          -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0, // v7-v4-v3-v2 down
          1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0 // v4-v7-v6-v5 back
        ]);

        var texCoords = new Float32Array([ // Texture coordinates
          1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // v0-v1-v2-v3 front
          0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, // v0-v3-v4-v5 right
          1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, // v0-v5-v6-v1 up
          1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // v1-v6-v7-v2 left
          0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, // v7-v4-v3-v2 down
          0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0 // v4-v7-v6-v5 back
        ]);

        var normals = new Float32Array([ // 每一个面的法向量
          0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, // v0-v1-v2-v3 front
          1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // v0-v3-v4-v5 right
          0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // v0-v5-v6-v1 up
          -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, // v1-v6-v7-v2 left
          0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, // v7-v4-v3-v2 down
          0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0 // v4-v7-v6-v5 back
        ]);

        var indices = new Uint8Array([ // Indices of the vertices
          0, 1, 2, 0, 2, 3, // front
          4, 5, 6, 4, 6, 7, // right
          8, 9, 10, 8, 10, 11, // up
          12, 13, 14, 12, 14, 15, // left
          16, 17, 18, 16, 18, 19, // down
          20, 21, 22, 20, 22, 23 // back
        ]);

        if (!initArrayBuffer(gl, "a_Position", vertices, 3, gl.FLOAT)) return -1; // 创建缓冲区并赋值attribute
        if (!initArrayBuffer(gl, "a_TexCoord", texCoords, 2, gl.FLOAT)) return -1; // 创建缓冲区并赋值attribute
        if (!initArrayBuffer(gl, "a_Normal", normals, 3, gl.FLOAT)) return -1; // 创建缓冲区并赋值attribute

        let indexBuffer = gl.createBuffer();
        if (!indexBuffer) {
          console.log(Error('Failed to create index buffer'));
          return -1;
        }
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW); // 写ELEMENT_ARRAY_BUFFER入缓冲区

        return indices.length;
      }

      function initTextures36(gl, n) {
        let texture = gl.createTexture(); // 创建纹理对象 // 省略错误处理
        let u_sampler = gl.getUniformLocation(gl.program, "u_Sampler"); // 获取 u_Sampler 存储位置 // 省略错误处理

        let image = new Image(); // 创建image图像
        image.onload = () => loadTexture36(gl, n, texture, u_sampler, image) // 注册图像加载事件的响应函数
          .then(() => addListener36()) // 添加事件监听
          .then(() => draw36(gl36, n36, g_viewProjMatrix36, u_mvpMatrix36, currentAngle36)); // 绘制
        image.src = "../texture/texture1.jpg"; // 浏览器加载图像

        return true;
      }

      function loadTexture36(gl, n, texture, u_sampler, image) {
        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); // 对纹理图像进行y轴翻转
        gl.activeTexture(gl.TEXTURE0); // 开启0号纹理单元
        gl.bindTexture(gl.TEXTURE_2D, texture); // 向target绑定纹理对象

        // 配置纹理参数
        // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

        //配置纹理参数
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image); // 配置纹理对象

        gl.uniform1i(u_sampler, 0); // 将0号纹理传递给着色器 // 省略错误处理

        return new Promise((resolve, reject) => resolve());
      }

      function addListener36() {
        console.log("开始添加事件");

        let drag_flag36 = false; // 是否在拖动
        let lastX = -1; // 鼠标最后的位置
        let lastY = -1; // 鼠标最后的位置

        c36.addEventListener("mousedown", event => { // 按下鼠标
          let x = event.clientX;
          let y = event.clientY;
          // 限制在 canvas 内拖动
          let rect = event.target.getBoundingClientRect();

          if (rect.left <= x && x < rect.right && rect.top <= y && rect.bottom > y) {
            lastX = x;
            lastY = y;
            drag_flag36 = true;
          }
        });

        c36.addEventListener("mouseup", event => drag_flag36 = false); // 松开鼠标

        c36.addEventListener("mousemove", event => { // 移动鼠标
          let x = event.clientX;
          let y = event.clientY;
          if (drag_flag36) {
            let factor = 100 / c36.height; // 旋转因子
            let dx = factor * (x - lastX);
            let dy = factor * (y - lastY);
            currentAngle36[0] = Math.max(Math.min(currentAngle36[0] + dy, 90.0), -90.0); // 控制角度
            // currentAngle36[0] = currentAngle36[0] + dy;
            currentAngle36[1] = currentAngle36[1] + dx;

            // draw36(gl36, n36, g_viewProjMatrix36, u_mvpMatrix36, currentAngle36);
          }
          lastX = x;
          lastY = y;
        });

        return new Promise((resolve, reject) => resolve());
      }

      function draw36(gl, n, g_viewProjMatrix36, u_mvpMatrix, currentAngle) {
        // g_viewProjMatrix36.setPerspective(30.0, 1, 1.0, 100.0); // 垂直视角、近裁剪面宽高比、近裁剪面位置、远裁剪面位置
        // g_viewProjMatrix36.lookAt(3, 3, 7, 0, 0, 0, 0, 1, 0); // 视点、视线（被观察对象位置）、上方向

        g_mvpMatrix36.setPerspective(30.0, 1, 1.0, 100.0); // 垂直视角、近裁剪面宽高比、近裁剪面位置、远裁剪面位置
        g_mvpMatrix36.lookAt(3, 3, 7, 0, 0, 0, 0, 1, 0); // 视点、视线（被观察对象位置）、上方向

        g_modelMatrix36.setRotate(currentAngle[0], 1, 0, 0); // X轴
        g_modelMatrix36.rotate(currentAngle[1], 0, 1, 0); // Y轴
        gl.uniformMatrix4fv(u_modelMatrix36, false, g_modelMatrix36.elements); // 传入 模型矩阵

        g_normalMatrix36.setInverseOf(g_modelMatrix36); // 取模型矩阵逆矩阵
        g_normalMatrix36.transpose(); // 取转置矩阵
        gl36.uniformMatrix4fv(u_normalMatrix36, false, g_normalMatrix36.elements); // 传入 魔法矩阵

        g_mvpMatrix36.multiply(g_modelMatrix36);
        gl36.uniformMatrix4fv(u_mvpMatrix36, false, g_mvpMatrix36.elements);

        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); // 清空颜色及深度缓冲区
        gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0); // 绘制
      }
    </script>
  </div>

</body>

</html>